#include "Common.h"
#include "ImageManager.h"
#include "Image.h"
#include "ImageCodecFreeImage.h"
#include "Utils/Util.h"
#include "Utils/Logger/Logger.h"

using namespace RayFrame;

IMPL_SINGLETON(ImageManager);

Image* ImageManager::CreateImage(STRING imageName, unsigned width, unsigned height, PixelFormat pf)
{
  int bpp = GetNumElemBytes(pf) * 8;
  Image* img = new Image();
  img->m_width = width;
  img->m_height = height;
  img->m_bpp = bpp;
  img->m_filename = "";
  img->m_format = pf;
  img->m_data = new unsigned char[ width * height * bpp / 8 ];

  
  if( img )
  {
    InsertData(imageName, img);
    Logger::InstanceRef().Write(LogNormal, "Image %s Created.", imageName.c_str());
    return img;
  }
  else
  {
    Logger::InstanceRef().Write(LogNormal, "Image %s Creation failed.", imageName.c_str());
    return NULL;
  }
}

DLL_DECLARE Image* ImageManager::LoadFromFile( STRING imageName, STRING filename )
{
  if(!FileExists(filename))
  {
    STRING newfilename = "../Resources/Textures/" + filename;
    if(!FileExists(newfilename))
      throw new MyException("Cannot find texture " + filename);
    filename = newfilename;
  }

  Image* img = ImageCodec::GetCodec()->LoadFromFile(filename);
  InsertData(imageName, img);
  if( img )
  {
    Logger::InstanceRef().Write(LogNormal, "Image loaded: %s.", filename.c_str());
    return img;
  }
  else
  {
    Logger::InstanceRef().Write(LogHigher, "Image loading failedL %s.", filename.c_str());
    return NULL;
  }
}

bool ImageManager::SaveToFile(Image* image, STRING filename, ImageFileFormat iff)
{
  bool result = ImageCodec::GetCodec()->SaveToFile(image, filename, iff);
  Logger::InstanceRef().Write(LogNormal, "Image %s saved.", filename.c_str());
  return result;
}

DLL_DECLARE int ImageManager::GetNumElemBytes(PixelFormat pf)
{
  int result = 0;
  switch(pf)
  {
  case PIXEL_UNKNOWN:
    result = 0;
    break;
  case PIXEL_L8:
    result = 1;
    break;
  case PIXEL_R5G6B5:
  case PIXEL_A1R5G5B5:
    result = 2;
    break;
  case PIXEL_R8G8B8:
  case PIXEL_B8G8R8:
    result = 3;
    break;
  case PIXEL_R8G8B8A8:
  case PIXEL_B8G8R8A8:
    result = 4;
    break;

  case PIXEL_RGB16:
    result = 6;
    break;
  case PIXEL_RGBA16:
    result = 8;
    break;
  case PIXEL_F32:
    result = 4;
    break;
  case PIXEL_F64:
    result = 8;
    break;
  case PIXEL_RGBF32:
    result = 12;
    break;
  case PIXEL_RGBAF32:
    result = 16;
    break;
  default:
    result = 0;
    WarningMsg("Undefined image pixel format.");
    break;
  }
  
  return result;
}

int ImageManager::GetComponentCount(PixelFormat pf)
{
  switch(pf)
  {
  case PIXEL_L8:
    return 1;
  case PIXEL_R5G6B5:
    return 3;
  case PIXEL_A1R5G5B5:
    return 4;
  case PIXEL_R8G8B8:
  case PIXEL_B8G8R8:
    return 3;
  case PIXEL_R8G8B8A8:
  case PIXEL_B8G8R8A8:
    return 4;
  
  case PIXEL_RGB16:
    return 3;
  case PIXEL_RGBA16:
    return 4;
  case PIXEL_F32:
  case PIXEL_F64:
    return 1;
  case PIXEL_RGBF32:
    return 4;
  case PIXEL_RGBAF32:
    return 4;
  default:
    assert(false);
    return 1;
  }
}

Image* ImageManager::GetDefaultImage()
{
  Image* result = SearchName("ReplaceMe.tif");
  if(result)
    return result;
  else
    return LoadFromFile("DefaultImage", "ReplaceMe.tif");
}